package iosu.java.games.razer;

/**
 * Esta clase implementa el mecanismo que hace que las vueltas en el bucle de juego
 * tengan un FPS constante ( o casi.. )
 * basado en el excelente articulo http://www.koonsolo.com/news/dewitters-gameloop/
 * @author iosu
 *
 */
public class ConstantFPSEngine {
	
	final int FPS = 30;
	final long ONE_SECOND = (long)1e9;
	int maxUpdates = 30; // fps max
	int frames = 0;
	int currentFPS = 0;
	long time, lastTime, diffTime, deltaTime;
	int updatecount;
	boolean useYield;
	
	public ConstantFPSEngine(boolean yield){
		this.useYield = yield;
	}
	
	/**
	 * inicializo el motor de FPS
	 * este metodo se llama antes de entrar en el bucle de juego
	 */
	public void init(){
		this.time= System.nanoTime();
		this.lastTime = System.nanoTime();
	}
	
	
	/**
	 * datos iniciales de cada vuelta del bucle de juego
	 * este metodo ha de llamarse al principio de cada vuelta en el bucle de juego 
	 */
	public void reset(){
		this.diffTime = System.nanoTime()-this.lastTime;   
		this.lastTime += this.diffTime;
		this.updatecount=0;
	}
	
	
	/**
	 * este metodo devuelve true si podemos seguir calculando posiciones del juego, o false
	 * si tenemos que salir a repintar el frame para mantener los FPS
	 * @return
	 */
	public boolean timeToUpdate(){
		return (diffTime > 0 && (maxUpdates <= 0 || updatecount < maxUpdates));
		
	}
	
	public long getDeltaTime(){
		this.deltaTime = this.FPS > 0 ? this.deltaTime = Math.min(this.diffTime,ONE_SECOND/FPS) : this.diffTime;
		return this.deltaTime;
	}
	
	public void updateLoop(){
		this.diffTime -= this.deltaTime;
		this.updatecount++;
	}
	
	public int getFPS(){
		return this.currentFPS;
	}
	
	public boolean updateFrame(){
		this.frames++;
//		System.out.println("frames: "+this.frames);
		if(System.nanoTime()-this.time >= ONE_SECOND) {
			this.time = System.nanoTime();
			currentFPS = frames;
			frames = 0;   
		}
		
		if(this.FPS > 0) {         
			long sleepTime = Math.round((ONE_SECOND/FPS)-(System.nanoTime()-lastTime));
			if(sleepTime <= 0){
//				System.out.println("sleepTime <= 0");
				return false;
			}
			
			long prevTime = System.nanoTime();
			while(System.nanoTime()-prevTime < sleepTime) {
				if(useYield){
					Thread.yield(); //Smoother game loop, more CPU usage
				}else{
					try{
						Thread.sleep(1); //Less CPU usage but not as smooth as yield()
					}catch(InterruptedException e){
						
					}
				}
			}
		}
		return true;
	}
	
	
}
